
#include <pthread.h>

#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
#include "libavcodec/opt.h"
#include "libavutil/pixdesc.h"
#include "libavdevice/avdevice.h"

#include "dmai_env.h"
#include "dmai_buffer.h"
#include "dmai_fifo.h"
#include "av_streamer.h"

#include "av_encode.h"

extern int avcodec_force_header (AVCodecContext *avctx);

#define MAX_AV_FRAMES		3
static HANDLE av_cap_in, av_cap_out;

HANDLE av_data_in, av_data_out;

int forceHeader = 0;

static AVCodecContext *av_h264;

static void
av_encode_thread (void)
{
	HANDLE data;
	AVFrame *frame;
	int ret;

	while (1) {
		if (fifo_get (av_cap_out, &frame))
			continue;
		if (forceHeader) {
			forceHeader = 0;
			avcodec_force_header (av_h264);
		}
		if (!fifo_get (av_data_in, &data)) {
			ret = avcodec_encode_video (av_h264, (uint8_t *)buffer_getUserPtr(data), buffer_getSize(data), frame);
			if (ret > 0) {
				buffer_setNumBytesUsed (data, ret);
				fifo_put (av_data_out, data);
			} else
				fifo_put (av_data_in, data);
		}
		fifo_put (av_cap_in, frame);
	}
}

int
av_encode_init(void)
{
	AVCodec *codec;
	pthread_t pid;
	int result = -1;
	int i;

	av_cap_in = fifo_create(MAX_AV_FRAMES);
	av_cap_out = fifo_create(MAX_AV_FRAMES);
	av_data_in = fifo_create(MAX_AV_FRAMES);
	av_data_out = fifo_create(MAX_AV_FRAMES);

	for (i=0; i<MAX_AV_FRAMES; i++) {
		fifo_put (av_cap_in, malloc(sizeof (AVFrame)));
		fifo_put (av_data_in, buffer_create(512*1024));
	}

	codec = avcodec_find_encoder(CODEC_ID_H264);
	if (codec == NULL) {
		fprintf(stderr, "avcodec_find_decoder error..\n");
		goto err1;
	}

	av_h264 = avcodec_alloc_context();

	av_h264->width = 1280;
	av_h264->height = 720;
	av_h264->bit_rate = 2000*1000;

	if (avcodec_open(av_h264, codec) < 0) {
		fprintf(stderr, "avcodec_open error..\n");
		goto err2;
	}
	if (pthread_create (&pid, NULL, (void *)av_encode_thread, NULL) != 0) {
		printf ("pthread_create av_encode_thread error!\n");
		goto err2;
	}
	return 0;
err2:
	
err1:
	fifo_delete (av_cap_in);
	fifo_delete (av_cap_out);
	return result;
}

void
av_encode_encode(AVPacket *pkt)
{
	AVFrame *frame;

	if (!fifo_get (av_cap_in, &frame)) {
		frame->data[0] = pkt->data;
		fifo_put (av_cap_out, frame);
	}
}
